﻿#define DEBUG

using System;
using System.Collections.Generic;
using System.Text;

using System.Runtime.InteropServices;
using System.Collections;
using System.Drawing;

using SuperMapLib;

namespace JR_RouteAlarm
{
    class Route : IRoute
    {
        /*定数*/
        public const string FLD_FEATURE_CD = Utility.FEATURE;
        public const string FLD_DAIBUN_CD = Utility.DAIBUN;
        public const string FLD_TSUUSHO_CD = Utility.TSUUSHO;
        public const string FLD_LABEL_TEXT = Utility.LABEL_TEXT;

        private soDataSource objSource = null;
        //private soDatasets objDSs = null;

        public Route(soDataSource objSource)
        {
            this.objSource = objSource;
            //this.objDSs = objSource.Datasets;
        }

        #region IRoute メンバ

        private string feature = String.Empty;
        public string Feature
        {
            get
            {
                return feature;
            }
            set
            {
                feature = value;
            }
        }

        private string daibun = String.Empty;
        public string Daibun
        {
            get
            {
                return daibun;
            }
            set
            {
                daibun = value;
            }
        }

        private string tsuusho = String.Empty;
        public string Tsuusho
        {
            get
            {
                return tsuusho;
            }
            set
            {
                tsuusho = value;
            }
        }

        public void MakeBufferForRoute(soDatasetVector objVector, soRecordset objRS)
        {
            soRecordset objSubRs = null;

            feature = objRS.GetFieldValue(FLD_FEATURE_CD).ToString();
            daibun = objRS.GetFieldValue(FLD_DAIBUN_CD).ToString();
            tsuusho = objRS.GetFieldValue(FLD_TSUUSHO_CD).ToString();

            objSubRs = objVector.Query(
                FLD_FEATURE_CD + " = '" + feature + "' and " +
                FLD_DAIBUN_CD + " = '" + daibun + "' and " +
                FLD_TSUUSHO_CD + " = '" + tsuusho + "'",
                true, null, "");

            if (objSubRs != null && objSubRs.RecordCount > 0)
            {
                if (!objSubRs.IsBOF())
                {
                    objSubRs.MoveFirst();
                }

                soGeoLine objFullRoute = null;
                soGeoLine objLineTmp = null;
                for (; !objSubRs.IsEOF(); objSubRs.MoveNext())
                {
                    objLineTmp = objSubRs.GetGeometry() as soGeoLine;
                    if (objFullRoute == null)
                    {
                        objFullRoute = objLineTmp;
                        continue;
                    }
                    if (!objFullRoute.Joint(objLineTmp))
                    {
                        Marshal.ReleaseComObject(objLineTmp);
                        objLineTmp = null;
                        objSubRs.Close();
                        Marshal.ReleaseComObject(objSubRs);
                        objSubRs = null;
                        Marshal.ReleaseComObject(objFullRoute);
                        objFullRoute = null;

                        throw new Exception("Joint line failed!");
                    }
                }
                objSubRs.Close();

                MakeBufferForPart(objFullRoute);

                Marshal.ReleaseComObject(objLineTmp);
                objLineTmp = null;
                Marshal.ReleaseComObject(objSubRs);
                objSubRs = null;
                Marshal.ReleaseComObject(objFullRoute);
                objFullRoute = null;
            }
        }

        private void MakeBufferForPart(soGeoLine objFullRoute)
        {
            soGeoPoint[] objPointsDividing = null;
            ArrayList lineList = new ArrayList();

            objPointsDividing = new soGeoPoint[Utility.MAX_CROSSING_POINTS];
            MakeDividingPointsOnRoute(objFullRoute, objPointsDividing);

            if (objFullRoute.SpatialRelation.Contains(objPointsDividing[0] as soGeometry))
            {
                MakeDividingBuffer(objFullRoute, objPointsDividing, 0, lineList);
            }
            else
            {
                throw new Exception("Point wrong!");
            }
        }

        private void MakeDividingBuffer(soGeoLine objLine, soGeoPoint[] objPoints, int idx, ArrayList lineList)
        {
            soGeoLine[] objLines = new soGeoLine[2];
            soPoint tmpPoint = null;
            soGeoRegion objBuffer = null;

            tmpPoint = new soPoint();
            objLines[0] = new soGeoLine();
            objLines[1] = new soGeoLine();

            tmpPoint.x = objPoints[idx].x;
            tmpPoint.y = objPoints[idx].y;
            if (objLine.Split(tmpPoint, objLines[0], objLines[1]))
            {
                if (objPoints[idx + 1] == null)
                {
                    objBuffer = objLines[0].SpatialOperator.Buffer2(
                        Utility.BUFFER_ALARM_DISTANCE_2, Utility.BUFFER_ALARM_DISTANCE_2, 0);
                    Utility.routeLnWithBfr[new object[2] { objLines[0], new string[3] { feature, daibun, tsuusho } }] = objBuffer;
                    objBuffer = objLines[1].SpatialOperator.Buffer2(
                        Utility.BUFFER_ALARM_DISTANCE_2, Utility.BUFFER_ALARM_DISTANCE_2, 0);
                    Utility.routeLnWithBfr[new object[2] { objLines[1], new string[3] { feature, daibun, tsuusho } }] = objBuffer;
                }
                else
                {
                    Boolean pointContain = false;

                    for (int twoIdx = 0; twoIdx < 2; twoIdx++)
                    {
                        pointContain = false;
                        for (int i = idx + 1; objPoints[i] != null; i++)
                        {
                            if (objLines[twoIdx].SpatialRelation.Contains(objPoints[i] as soGeometry))
                            {
                                pointContain = true;
                                MakeDividingBuffer(objLines[twoIdx], objPoints, i, lineList);
                                break;
                            }
                        }
                        if (!pointContain)
                        {
                            objBuffer = objLines[twoIdx].SpatialOperator.Buffer2(
                                Utility.BUFFER_ALARM_DISTANCE_2, Utility.BUFFER_ALARM_DISTANCE_2, 0);
                            Utility.routeLnWithBfr[new object[2] { objLines[twoIdx], new string[3] { feature, daibun, tsuusho } }] = objBuffer;
                        }
                    }



                    //if (objLines[0].SpatialRelation.Contains(objPoints[idx + 1] as soGeometry))
                    //{
                    //    //pointContain = true;
                    //    lineList.Add(objLines[1]);
                    //    MakeDividingBuffer(objLines[0], objPoints, idx + 1, lineList);
                    //}
                    //else if (objLines[1].SpatialRelation.Contains(objPoints[idx + 1] as soGeometry))
                    //{
                    //    //pointContain = true;
                    //    lineList.Add(objLines[0]);
                    //    MakeDividingBuffer(objLines[1], objPoints, idx + 1, lineList);
                    //}
                    //else
                    //{
                    //    soGeoLine objLineTmp = null;
                    //    int lineCount = lineList.Count;
                    //    //foreach (object obj in lineList)
                    //    for (int i = 0; i < lineCount; i++)
                    //    {
                    //        if (lineList[i] == null)
                    //        {
                    //            break;
                    //        }
                    //        objLineTmp = lineList[i] as soGeoLine;
                    //        //objLineTmp = obj as soGeoLine;
                    //        if (objLineTmp.SpatialRelation.Contains(objPoints[idx + 1] as soGeometry))
                    //        {
                    //            //pointContain = true;
                    //            MakeDividingBuffer(objLineTmp, objPoints, idx + 1, lineList);
                    //            //break;
                    //        }
                    //    }
                    //}

                    //if (!pointContain)
                    //{
                    //    objBuffer = objLines[0].SpatialOperator.Buffer2(
                    //        Utility.BUFFER_ALARM_DISTANCE_2, Utility.BUFFER_ALARM_DISTANCE_2, 0);
                    //    Utility.routeLnWithBfr[new object[2] { objLines[0], new string[3] { feature, daibun, tsuusho } }] = objBuffer;
                    //    objBuffer = objLines[1].SpatialOperator.Buffer2(
                    //        Utility.BUFFER_ALARM_DISTANCE_2, Utility.BUFFER_ALARM_DISTANCE_2, 0);
                    //    Utility.routeLnWithBfr[new object[2] { objLines[1], new string[3] { feature, daibun, tsuusho } }] = objBuffer;
                    //}
                }
            }
            //else
            //{
            //    objBuffer = objLine.SpatialOperator.Buffer2(
            //        Utility.BUFFER_ALARM_DISTANCE_2, Utility.BUFFER_ALARM_DISTANCE_2, 0);
            //    Utility.routeLnWithBfr[new object[2] { objLine, new string[3] { feature, daibun, tsuusho } }] = objBuffer;
            //}

            Marshal.ReleaseComObject(tmpPoint);
            tmpPoint = null;
            //Marshal.ReleaseComObject(objBuffer);
            //objBuffer = null;
            Marshal.ReleaseComObject(objLines[0]);
            objLines[0] = null;
            Marshal.ReleaseComObject(objLines[1]);
            objLines[1] = null;
        }

        private void MakeDividingPointsOnRoute(soGeoLine objRoute, soGeoPoint[] objPointsCrossing)
        //private void MakeDividingPointsOnRoute(soGeoLine objRoute, ArrayList tmpList)
        {
            soDatasets objDSs = null;
            //soDataset objDSPoint = null;
            //soDatasetVector objDatasetV = null;
            //soRecordset objRS = null;
            //soGeoPoint objPointTmp = null;
            //soGeoPoint[] objPointsCrossing = null;
            soGeoRegion[] objBuffers = null;

            objBuffers = new soGeoRegion[Utility.MAX_ROUTES];
            //objPointsCrossing = new soGeoPoint[Utility.MAX_CROSSING_POINTS];
            objDSs = objSource.Datasets;

            FindCrossingPointsFromBuffers(objRoute, objBuffers, objPointsCrossing, objDSs);

            #region 広くポイントを取る
            /*
            objDSPoint = objDSs["キロ標_大宮"];
            //objDatasetV = objDSPoint as soDatasetVector;
            soDataset objDSCopy = null;
            soDatasetVector objDatasetVCopy = null;
            soRecordset objRSCopy = null;

            if (!objSource.IsAvailableDatasetName("datasetCopy"))
            {
                objSource.DeleteDataset("datasetCopy");
            }
            objDSCopy = objSource.CopyDataset(
                objDSPoint, "datasetCopy", false, seEncodedType.scEncodedNONE);
            objDatasetVCopy = objDSCopy as soDatasetVector;
            objRSCopy = objDatasetVCopy.Query("-1 < 0", true, null, "");

            if (objRSCopy != null && objRSCopy.RecordCount > 0)
            {
                if (objRSCopy.IsEOF())
                {
                    objRSCopy.MoveFirst();
                }

                //soGeometry objMetry = null;
                for (; !objRSCopy.IsEOF(); objRSCopy.MoveNext())
                { 
                    //objMetry = objRS.GetGeometry();
                    if (!objRoute.SpatialRelation.Contains(objRSCopy.GetGeometry()))
                    {
                        objRSCopy.Delete();
                    }
                }
                if (!objSource.IsAvailableDatasetName("tmpPointsOnLine"))
                {
                    objSource.DeleteDataset("tmpPointsOnLine");
                }
                objDatasetV = objSource.RecordsetToDataset(objRSCopy, "tmpPointsOnLine", false);
                objRSCopy.Close();
                objDatasetVCopy.Close();
                objDatasetVCopy.ClearRecordsets();
                objSource.DeleteDataset("datasetCopy");

                Marshal.ReleaseComObject(objRSCopy);
                objRSCopy = null;
                Marshal.ReleaseComObject(objDatasetVCopy);
                objDatasetVCopy = null;
                Marshal.ReleaseComObject(objDSCopy);
                objDSCopy = null;

                soPoint tmpPoint = null;
                for (int i = 0; i < Utility.MAX_CROSSING_POINTS; i++)
                {
                    if (objPointsCrossing[i] == null)
                    {
                        break;
                    }
                    objRS = objDatasetV.QueryByDistance(
                        objPointsCrossing[i] as soGeometry, Utility.KIROTEI_DISTANCE, "");
                    if (objRS != null && objRS.RecordCount > 0)
                    {
                        objRS.MoveFirst();
                        for (; !objRS.IsEOF(); objRS.MoveNext())
                        {
                            objPointTmp = objRS.GetGeometry() as soGeoPoint;
                            tmpPoint = new soPoint();
                            tmpPoint.x = Math.Ceiling(objPointTmp.x);
                            tmpPoint.y = Math.Ceiling(objPointTmp.y);
                            for (int j = 0; j < objBuffers.Length; j++)
                            {
                                if (objBuffers[j] == null)
                                {
                                    break;
                                }
                                if (!objPointTmp.SpatialRelation.Within(objBuffers[j] as soGeometry))
                                {
#if RELEASE
                                    objPointTmp = objRS.GetGeometry() as soGeoPoint;
#endif
                                    //objPointsDividing[i] = objPointTmp;
                                    if (!tmpList.Contains(tmpPoint))
                                    {
#if DEBUG
                                        Console.WriteLine("x={0}, y={1}, j={2}, i={3}", objPointTmp.x, objPointTmp.y, j, i);
#endif
                                        tmpList.Add(tmpPoint);
                                        //dividingPoints.Add2(objPointTmp.x, objPointTmp.y);
                                    }
                                    continue;
                                }
                            }
                        }
                        objRS.Close();
                    }
                }
                objDatasetV.Close();
                objDatasetV.ClearRecordsets();
                objSource.DeleteDataset("tmpPointsOnLine");

                //Marshal.ReleaseComObject(objMetry);
                //objMetry = null;
            }
             */
            #endregion

            //Marshal.ReleaseComObject(objPointTmp);
            //objPointTmp = null;
            //Marshal.ReleaseComObject(objDatasetV);
            //objDatasetV = null;
            //Marshal.ReleaseComObject(objRS);
            //objRS = null;
            //Marshal.ReleaseComObject(objDSPoint);
            //objDSPoint = null;
        }

        private void FindCrossingPointsFromBuffers(soGeoLine objRoute, soGeoRegion[] objBuffers, soGeoPoint[] objPointsCrossing, soDatasets objDSs)
        {
            soDataset objDSRegion = null;
            soDatasetVector objDatasetV = null;
            soRecordset objRS = null;
            soPoints tmpPoints = null;
            soGeometry objMetry = null;
            int regionIdx = 0;
            int pointIdx = 0;

            for (int i = 1; i <= objDSs.Count; i++)
            {
                if (objDSs[i].GetDatasetInfo().Name.StartsWith(Utility.BUFFER_TITLE_1000, true, null))
                {
                    objDSRegion = objDSs[i];
                    objDatasetV = objDSRegion as soDatasetVector;
                    objRS = objDatasetV.Query("-1 < 0", true, null, "");
                    if (objRS != null && objRS.RecordCount > 0)
                    {
                        objRS.MoveFirst();
                    }
                    objMetry = objRS.GetGeometry();
                    objRS.Close();
                    objDatasetV.Close();
                    objDatasetV.ClearRecordsets();

                    if (objRoute.SpatialRelation.Crosses(objMetry))
                    {
                        tmpPoints = objRoute.GetCrossings(objMetry);
                        objBuffers[regionIdx++] = objMetry as soGeoRegion;

                        int j = 0;
                        for (; j < tmpPoints.Count; j++)
                        {
                            objPointsCrossing[pointIdx + j] = new soGeoPoint();
                            objPointsCrossing[pointIdx + j].x = tmpPoints[j + 1].x;
                            objPointsCrossing[pointIdx + j].y = tmpPoints[j + 1].y;
                        }
                        pointIdx += j;
                    }
                }
            }

            if (tmpPoints != null)
            {
                Marshal.ReleaseComObject(tmpPoints);
                tmpPoints = null;
            }
            Marshal.ReleaseComObject(objDSRegion);
            objDSRegion = null;
            Marshal.ReleaseComObject(objRS);
            objRS = null;
            Marshal.ReleaseComObject(objDatasetV);
            objDatasetV = null;
        }

        #endregion
    }
}
